package com.yonyou.pmclouds.basecom.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yonyou.pmclouds.basecom.conf.NCInvokerConfiguration;
import com.yonyou.pmclouds.basecom.consts.BillTypeConst;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.project.entity.ProjectVO;
import com.yonyou.pmclouds.project.rmiitf.ProjectMaintain;
import com.yonyou.pmclouds.project.rmiitf.ProjectSimpleQuery;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
public class BillDrivenImpl {
    public static final String ACTION_APPROVED = "approved";
    public static final String PROJECT_CONST = "pk_project";
    public static final String PK_BILL_CONST = "pk_bill";
    public static final String BILL_TYPE_CONST = "bill_type";
    public static final String TRANSI_TYPE_CONST = "transi_type";
    public static final String ACTION_CONST = "action";
    public static final String ADDITION_CONST = "addition";
    public static final String UPDATE_SUCCESS_CODE = "update success";
    public static final String FLAG_CONST = "flag";
    public static final String PK_PROJECT_STATE_CONST = "pk_projectstate";
    public static final String SERVICE_NAME = "billDriven";
    public static final String NC_SERVICE_SERVLET_PATH = "/service/PMCloudDriveProjectStateServlet";
    public static final String NC_UBL_SERVICE = "nc.impl.pim.pimpub.cloud.PMCloudDriveProjectStateImpl";
    public static final String ACCEPT_BILL_TYPE = "4D36";
    public static final String ACCEPT_TRANSI_TYPE = "4D36-03";
    public static final String START_NC_BILL_TYPE = "4D23";
    public static final String START_NC_TRANSI_TYPE = "4D23-01";

    public interface BillDrivenInvoker {
        void invokeDriven(DrivenInvokeInfo info, String action, Map<String, Object> additionalInfo) throws BusinessException;
    }

    @Setter
    @Getter
    public static class DrivenInvokeInfo {
        private String billType;
        private String pkBill;
        private String pkProject;
        private String pkTenant;
    }

    @Setter
    @Getter
    public static class DrivenResult {
        private String billType;
        private String pkBill;
        private String pkProject;
        private String pkTenant;
    }

    // 这里暂时不考虑友工程内部存在单据状态驱动
    // 需要处理外部系统的异常处理
    @Component
    public static class BillDrivenInvokerImpl implements BillDrivenInvoker {
        @Autowired
        private ProjectSimpleQuery projectQuery;
        @Autowired
        private ProjectMaintain maintain;
        @Autowired
        private NCInvokerConfiguration.Invoker invoker;

        private ObjectMapper mapper = new ObjectMapper();

        @Override
        public void invokeDriven(final DrivenInvokeInfo info, String action, Map<String, Object> additionalInfo) throws BusinessException {
            // 判断是否需要单据驱动
            final ProjectVO project = projectQuery.queryProject(info.pkProject);
            if (project == null) {
                return;
            }
            // 目前，非nc项目不需要单据驱动
            if (project.getSrcType() == null) {
                return;
            }
            Map<String, Object> params = new HashMap<>();
            params.put(PROJECT_CONST, project.getPkSrc());
            String billType = null, transiType = null;
            if (BillTypeConst.COMPREHENSIVE_ACCEPTANCE_BILLTYPE.equals(info.billType)) {
                billType = ACCEPT_BILL_TYPE;
                transiType = ACCEPT_TRANSI_TYPE;
            } else if(BillTypeConst.WORKSTART_BILLTYPE.equals(info.billType)){
                billType = START_NC_BILL_TYPE;
                transiType = START_NC_TRANSI_TYPE;
            }
            else {
                billType = info.billType;
                transiType = info.billType;
            }
            params.put(BILL_TYPE_CONST, billType);
            params.put(TRANSI_TYPE_CONST, transiType);
            params.put(PK_BILL_CONST, info.pkBill);
            params.put(ACTION_CONST, action);
            if (additionalInfo != null && !additionalInfo.isEmpty()) {
                params.put(ADDITION_CONST, additionalInfo);
            }

            invoker.invokeAsync(SERVICE_NAME, NC_SERVICE_SERVLET_PATH, params, info.getPkTenant(), RuntimeEnvironment.getLoginUserId(), new NCInvokerConfiguration.CallBack() {
                private String pkProject = info.pkProject;

                @Override
                public void whenResult(NCInvokerConfiguration.Result result) throws BusinessException {
                    if (NCInvokerConfiguration.Result.STATUS_OK.equals(result.getStatus())) {
                        if (result.getResult() == null) {
                            return;
                        }
                        try {
                            String s = result.getResult();
                            Map map = mapper.readValue(s, Map.class);
                            if (!UPDATE_SUCCESS_CODE.equals(map.get(FLAG_CONST))) {
                                log.error("bill driven failed，info is {}", result);
                                return;
                            }
                            maintain.updateForNCBillDriven(pkProject, (String) map.get(PK_PROJECT_STATE_CONST));
                        } catch (IOException e) {
                            log.error("unserialization failed, result is {}", result.getResult());
                        }
                        //  这里建议考虑多个单据更新一个项目状态的时候，保证状态的最终一致
                    } else {
                        // TODO 记录错误信息，供后续调整数据
                        log.error("bill driven failed，info is {}", result);
                    }
                }
            });
        }
    }

}
